<script setup lang="ts">
import ReturnButton from '@/components/ReturnButton.vue'
import {onHide, onLoad, onShow, onUnload} from '@dcloudio/uni-app'
import {computed, reactive, ref} from 'vue'
import type {
  DriverReceiveOrderVO, FeeRuleVO,
  OrderEstimateInfoVO,
  OrderLocationDTO,
  OrderStartInfoVO,
  PassengerReceiveOrderVO,
} from '@/types/order'
import {
  arriveEndAPI,
  cancelOrderAPI,
  driverGetReceiveOrderInfoAPI,
  estimateOrderInfoAPI, getOrderFeeRuleAPI, getOrderPayInfoAPI,
  getOrderStartInfoAPI,
  passengerGetReceiveOrderInfoAPI, payOrderAPI,
  startServiceAPI,
  submitOrderAPI,
} from '@/api/order'
import useUserInfoStore from '@/stores/userInfo'
import {useMessage, useToast} from 'wot-design-uni'
import useCityCodeStore from '@/stores/cityCode'
import {CouponType, DriverStatus, OrderStatus, Role} from '@/types/constants'
import useTokenStore from '@/stores/token'
import type {DriverLocationDTO} from '@/types/map'
import {deleteDriverLocationAPI, updateDriverLocationAPI} from '@/api/map'
import useDriverIdStore from '@/stores/driverId'
import type {CouponRecordVO} from '@/types/reward'
import Coupon from '@/components/Coupon.vue'
import {getCanUseCouponByAmountAPI} from "@/api/reward";

const toast = useToast()
const message = useMessage()
const role = ref<Role>(Role.PASSENGER)
const { cityCode } = useCityCodeStore()
const { driverId } = useDriverIdStore()
const locationDTO = reactive<OrderLocationDTO>({
  phone: '',
  cityCode: '',
  startLocation: '',
  endLocation: '',
  startLongitude: 0,
  startLatitude: 0,
  endLongitude: 0,
  endLatitude: 0,
})
const markers = reactive([
  {
    id: 0,
    latitude: locationDTO.startLatitude,
    longitude: locationDTO.startLongitude,
    iconPath: '../../static/images/start.png',
    width: 40,
    height: 40,
  },
  {
    id: 1,
    latitude: locationDTO.endLatitude,
    longitude: locationDTO.endLongitude,
    iconPath: '../../static/images/end.png',
    width: 40,
    height: 40,
  },
])
type Location = {
  latitude: number
  longitude: number
}
const longitude = ref<number>(116.397505)
const latitude = ref<number>(39.908675)
const includePoints = reactive<Location[]>([])
const polyline = reactive([
  {
    points: [] as Location[],
    color: '#07C160',
    width: 10,
    arrowLine: true,
  },
])
const orderEstimateInfoVO = reactive<OrderEstimateInfoVO>({
  estimatePolyline: [],
  estimateDistance: '0',
  estimateDuration: 0,
  estimateFee: '0',
})
const passengerReceiveOrderVO = reactive<PassengerReceiveOrderVO>({
  id: 0,
  driverAvatar: '',
  driverName: '',
  carBrand: '',
  carColor: '',
  plateNumber: '',
  orderStatus: OrderStatus.WAIT,
  distance: '0',
  duration: 0,
  polyline: [],
})
const driverReceiveOrderVO = reactive<DriverReceiveOrderVO>({
  id: 0,
  driverId: 0,
  startLocation: '',
  orderStatus: OrderStatus.WAIT,
  distance: '0',
  duration: 0,
  polyline: [],
})
const orderId = ref<number>(0)
const distance = ref<string>('0')
const duration = ref<number>(0)
const locationName = ref<string>('')
const orderStatus = ref(OrderStatus.WAIT)

const calculatePolyline = (route: number[]) => {
  polyline[0].points = []
  for (let i = 0; i < route.length; i++) {
    if (i > 1) route[i] = Number((route[i - 2] + route[i] / 1000000).toFixed(6))
    if (i % 2 === 1) polyline[0].points.push({ latitude: route[i - 1], longitude: route[i] })
  }
  includePoints.length = 0
  const len = polyline[0].points.length
  includePoints.push(
      { latitude: polyline[0].points[0].latitude, longitude: polyline[0].points[0].longitude },
      { latitude: polyline[0].points[len - 1].latitude, longitude: polyline[0].points[len - 1].longitude },
  )
  const map = uni.createMapContext('map')
  map.includePoints({ points: includePoints, padding: [0, 80, 100, 80] })
}

const uploadTimer = ref<number | undefined>()
const driverLocationDTO = reactive<DriverLocationDTO>({
  cityCode: '',
  longitude: 0,
  latitude: 0,
  driverInfo: {
    driverId: driverId as number,
    driverStatus: DriverStatus.BUSY,
  },
})
const uploadDriverLocation = (driverStatus: DriverStatus) => {
  uni.getLocation({
    type: 'gcj02',
    isHighAccuracy: true,
    success: (res) => {
      driverLocationDTO.latitude = res.latitude
      driverLocationDTO.longitude = res.longitude
      driverLocationDTO.driverInfo.driverStatus = driverStatus
      updateDriverLocationAPI(driverLocationDTO)
    },
    fail: () => {
      toast.show('获取位置失败，请开启定位')
    },
  })
}
onLoad(async (option) => {
  const userInfoStore = useUserInfoStore()
  const userInfo = userInfoStore.userInfo
  if (option) {
    if (option.orderId) {
      role.value = userInfo?.role as Role
      orderId.value = Number(option.orderId)
      uni.getLocation({
        type: 'gcj02',
        isHighAccuracy: true,
        success: (res) => {
          longitude.value = res.longitude
          latitude.value = res.latitude
        },
        fail: () => {
          toast.show('获取位置失败，请开启定位')
        },
      })
      markers.pop()
      if (role.value === Role.DRIVER) {
        driverLocationDTO.cityCode = cityCode as string
        const res = await driverGetReceiveOrderInfoAPI(orderId.value)
        if (res.code === 200 && res.data.id === orderId.value) {
          Object.assign(driverReceiveOrderVO, res.data)
          distance.value = driverReceiveOrderVO.distance
          duration.value = driverReceiveOrderVO.duration
          locationName.value = driverReceiveOrderVO.startLocation
          orderStatus.value = driverReceiveOrderVO.orderStatus
          calculatePolyline(driverReceiveOrderVO.polyline)
          markers[0].longitude = polyline[0].points[polyline[0].points.length - 1].longitude
          markers[0].latitude = polyline[0].points[polyline[0].points.length - 1].latitude
          await deleteDriverLocationAPI(
            driverLocationDTO.cityCode,
            driverLocationDTO.driverInfo.driverId
          )
          uploadDriverLocation(DriverStatus.BUSY)
          uploadTimer.value = setInterval(() => {
            uploadDriverLocation(DriverStatus.BUSY)
          }, 10000)
        }
      }
      else {
        const res = await passengerGetReceiveOrderInfoAPI(orderId.value)
        if (res.code === 200 && res.data.id === orderId.value) {
          Object.assign(passengerReceiveOrderVO, res.data)
          distance.value = passengerReceiveOrderVO.distance
          duration.value = passengerReceiveOrderVO.duration
          orderStatus.value = passengerReceiveOrderVO.orderStatus
          calculatePolyline(passengerReceiveOrderVO.polyline)
        }
      }
    } else if (option.locationDTO) {
      locationDTO.phone = userInfoStore.userInfo!.phone
      Object.assign(locationDTO, JSON.parse(option.locationDTO))
      locationDTO.cityCode = cityCode as string
      markers[0].latitude = locationDTO.startLatitude
      markers[0].longitude = locationDTO.startLongitude
      markers[1].latitude = locationDTO.endLatitude
      markers[1].longitude = locationDTO.endLongitude
      const res = await estimateOrderInfoAPI({
        startLongitude: locationDTO.startLongitude,
        startLatitude: locationDTO.startLatitude,
        endLongitude: locationDTO.endLongitude,
        endLatitude: locationDTO.endLatitude,
      })
      if (res.code === 200) {
        Object.assign(orderEstimateInfoVO, res.data)
        calculatePolyline(orderEstimateInfoVO.estimatePolyline)
      }
    }
  }
})

const socketTask = ref<UniNamespace.SocketTask | null>(null)
const loadOrder = (data: OrderStartInfoVO) => {
  distance.value = data.estimateDistance
  duration.value = data.estimateDuration
  locationName.value = data.endLocation
  orderStatus.value = data.orderStatus
  calculatePolyline(data.estimatePolyline)
  markers[0].longitude = data.startLongitude
  markers[0].latitude = data.startLatitude
  markers.push({
    id: 1,
    latitude: data.endLatitude,
    longitude: data.endLongitude,
    iconPath: '../../static/images/end.png',
    width: 40,
    height: 40,
  })
  Object.assign(includePoints, [])
  includePoints.push(
    { latitude: data.startLatitude, longitude: data.startLongitude },
    { latitude: data.endLatitude, longitude: data.endLongitude },
  )
  const map = uni.createMapContext('map')
  map.includePoints({ points: includePoints, padding: [0, 80, 100, 80] })
}
const websocket = () => {
  socketTask.value = uni.connectSocket({
    url: 'ws://' + url.substring(url.indexOf('//') + 2) + '/order/ws/order/' + orderId.value,
    header: { Authorization: 'Bearer ' + token },
    complete: () => {},
  })
  socketTask.value.onMessage(async (res) => {
    const data = JSON.parse(res.data) as OrderStatusVO
    if (data.orderId == orderId.value) {
      if (data.orderStatus === OrderStatus.RECEIVE) {
        const res = await passengerGetReceiveOrderInfoAPI(orderId.value)
        if (res.code !== 200) return toast.show(res.msg)
        Object.assign(passengerReceiveOrderVO, res.data)
        distance.value = passengerReceiveOrderVO.distance
        duration.value = passengerReceiveOrderVO.duration
        orderStatus.value = passengerReceiveOrderVO.orderStatus
        calculatePolyline(passengerReceiveOrderVO.polyline)
        markers.pop()
        clearInterval(timer.value!)
        timer.value = undefined
      }
      else if (data.orderStatus === OrderStatus.PERFORM) {
        const res = await getOrderStartInfoAPI(orderId.value)
        if (res.code !== 200) return toast.show(res.msg)
        loadOrder(res.data)
      }
      else if (data.orderStatus === OrderStatus.PAYMENT) {
        const res = await getOrderPayInfoAPI(orderId.value)
        if (res.code !== 200) return toast.show(res.msg)
        startTime.value = res.data.startTime
        realFee.value = res.data.realFee
        orderStatus.value = res.data.orderStatus
        calculatePolyline(res.data.realPolyline)
        markers[0].longitude = res.data.startLongitude
        markers[0].latitude = res.data.startLatitude
        markers.push({
          id: 1,
          latitude: res.data.endLatitude,
          longitude: res.data.endLongitude,
          iconPath: '../../static/images/end.png',
          width: 40,
          height: 40,
        })
      }
    }
  })
}
onShow(() => {
  if (orderId.value != 0 && role.value === Role.PASSENGER) {
    websocket()
  }
})

const time = ref<number>(0)
const formatTime = computed(
  () =>
    `${String(Math.floor(time.value / 60)).padStart(2, '0')}:${String(time.value % 60).padStart(2, '0')}`,
)
const timer = ref<number | undefined>(undefined)
const { token } = useTokenStore()
const url: string = import.meta.env.VITE_API_URL
type OrderStatusVO = {
  orderId: number
  orderStatus: OrderStatus
}
const submitOrder = async () => {
  if (timer.value) {
    // 取消订单
    const res = await cancelOrderAPI(orderId.value)
    if (res.code !== 200) return toast.show(res.msg)
    if (socketTask.value) socketTask.value.close({})
    clearInterval(timer.value)
    timer.value = undefined
  } else {
    // 提交订单
    const res = await submitOrderAPI(locationDTO)
    if (res.code !== 200) return toast.show(res.msg)
    orderId.value = res.data
    orderStatus.value = OrderStatus.WAIT
    time.value = 0
    timer.value = setInterval(() => {
      time.value++
    }, 1000)
    websocket()
  }
}

const initText = '到达起点'
const buttonText = ref(initText)
const passengerPhone = ref('')
const clickButton = async (status: OrderStatus) => {
  if (status === OrderStatus.RECEIVE) {
    if (buttonText.value === initText) buttonText.value = '开始服务'
    else {
      message
        .prompt({
          title: '请询问并输入乘客手机尾号后四位',
          inputValue: passengerPhone.value,
          inputPattern: /^\d{4}$/,
          inputError: '请输入四位数字',
        })
        .then(async (res) => {
          const res1 = await startServiceAPI(orderId.value, res.value as string)
          if (res1.code !== 200) return toast.show(res1.msg)
          const res2 = await getOrderStartInfoAPI(orderId.value)
          if (res2.code !== 200) return toast.show(res2.msg)
          buttonText.value = '到达终点'
          loadOrder(res2.data)
        })
        .catch(() => {})
    }
  } else if (status === OrderStatus.PERFORM) {
    const res = await arriveEndAPI(orderId.value)
    if (res.code !== 200) return toast.show(res.msg)
    toast.show('订单已完成，3秒后将跳转首页')
    setTimeout(() => {
      uni.navigateBack()
    }, 3000)
  }
}

const title = computed(() => {
  if (orderStatus.value === OrderStatus.RECEIVE) return '智行打车司机正在赶来'
  else if (orderStatus.value === OrderStatus.PERFORM) return '正在前往目的地'
  else if (orderStatus.value === OrderStatus.PAYMENT) {
    setTimeout(() => {
      if (socketTask.value) socketTask.value.close({})
    }, 3000)
    return '订单待支付'
  }
  else if (orderStatus.value === OrderStatus.COMPLETE) return '订单已完成'
  else if (orderStatus.value === OrderStatus.CANCEL) return '订单已取消'
})

const startTime = ref('')
const timePeriod = computed(() => {
  if (startTime.value == '') return '普通时段'
  else {
    const start = '06:00:00'
    const end = '21:59:59'
    return startTime.value >= start && startTime.value <= end ? '普通时段' : '夜间时段'
  }
})
const showFeeDetail = ref(false)
const showCoupon = ref(false)
const couponRecordVO = reactive<CouponRecordVO[]>([])
const formatter = new Intl.NumberFormat('en-US', {
  minimumFractionDigits: 0,
  maximumFractionDigits: 2
})
const realFee = ref('0')
const realPayment = computed(() => {
  if (couponId.value === 0 || couponRecordVO.length === 0) return realFee.value
  for (let i = 0; i < couponRecordVO.length; i++) {
    if (couponRecordVO[i].id === couponId.value) {
      if (couponRecordVO[i].couponType === CouponType.CASH_COUPON) {
        return formatter.format(Number(realFee.value) - Number(couponRecordVO[i].amount))
      }
      else {
        return formatter.format(Number(realFee.value) * Number(couponRecordVO[i].discount))
      }
    }
  }
  return realFee.value
})
const selectCoupon = async () => {
  const res = await getCanUseCouponByAmountAPI(realFee.value)
  if (res.code === 200) Object.assign(couponRecordVO, res.data)
  showCoupon.value = true
}
const couponId = ref(0)
const clickCoupon = (id: number, radio: boolean) => {
  couponId.value = radio ? id : 0
}
const feeRuleVO = reactive<FeeRuleVO>({
  totalFee: '',
  startingFee: '',
  distanceFee: '',
  longDistanceFee: '',
  baseDistance: '',
  exceedDistance: '',
  exceedDistancePrice: '',
  baseLongDistance: '',
  exceedLongDistance: '',
  exceedLongDistancePrice: ''
})
const clickFeeRule = async () => {
  const res = await getOrderFeeRuleAPI(orderId.value)
  if (res.code === 200) Object.assign(feeRuleVO, res.data)
  showFeeDetail.value = true
}
const payOrder = async () => {
  const res = await payOrderAPI(orderId.value, couponId.value !== 0 ? couponId.value : null)
  if (res.code !== 200) return toast.show(res.msg)
  toast.show('支付成功，3秒后将跳转首页')
  setTimeout(() => {
    uni.navigateBack()
  }, 3000)
}

onHide(() => {
  clearInterval(uploadTimer.value)
  clearInterval(timer.value!)
  timer.value = undefined
  uploadTimer.value = undefined
  if (socketTask.value) socketTask.value.close({})
  if (role.value === Role.DRIVER) {
    deleteDriverLocationAPI(
        driverLocationDTO.cityCode,
        driverLocationDTO.driverInfo.driverId,
    )
  }
})
onUnload(() => {
  clearInterval(uploadTimer.value)
  clearInterval(timer.value!)
  timer.value = undefined
  uploadTimer.value = undefined
  if (socketTask.value) socketTask.value.close({})
  if (role.value === Role.DRIVER) {
    deleteDriverLocationAPI(
        driverLocationDTO.cityCode,
        driverLocationDTO.driverInfo.driverId,
    )
  }
})
</script>

<template>
  <wd-toast />
  <wd-message-box />
  <ReturnButton />
  <map
    id="map"
    :polyline="polyline"
    :markers="markers"
    :latitude="latitude"
    :longitude="longitude"
    style="width: 100%; height: 100%"
    :show-location="true"
  />
  <view v-if="orderStatus === OrderStatus.WAIT" class="content">
    <view class="info">
      <view class="item">
        <view>预估距离：</view>
        <view>{{ orderEstimateInfoVO.estimateDistance }}公里</view>
      </view>
      <view class="item">
        <view>预估用时：</view>
        <view>{{ orderEstimateInfoVO.estimateDuration }}分钟</view>
      </view>
      <view class="item">
        <view>预估费用：</view>
        <view>{{ orderEstimateInfoVO.estimateFee }}元</view>
      </view>
    </view>
    <view class="button">
      <wd-button @click="submitOrder" block custom-style="margin-top: 20rpx;">{{
        timer ? formatTime + ' 取消' : '立即打车'
      }}</wd-button>
    </view>
  </view>
  <view v-else class="orderInfo">
    <view class="status">{{ title }}</view>
    <view v-if="orderStatus === OrderStatus.PAYMENT" class="payment">
      <view class="paymentFee">{{ realPayment }}元</view>
      <view class="realFee">
        <view>订单总额</view>
        <wd-popup v-model="showFeeDetail" closable custom-style="border-radius:32rpx;">
          <view class="feeRule">
            <view class="title">费用详情</view>
            <view class="detail">
              <view class="item">
                <view>起步价({{timePeriod}}，{{feeRuleVO.baseDistance}}公里)</view>
                <view>{{feeRuleVO.startingFee}}元</view>
              </view>
              <view v-if="Number(feeRuleVO.distanceFee) > 0" class="item">
                <view>里程费({{timePeriod}}，{{feeRuleVO.exceedDistance}}公里)</view>
                <view>{{feeRuleVO.distanceFee}}元</view>
              </view>
              <view v-if="Number(feeRuleVO.longDistanceFee) > 0" class="item">
                <view>长途费({{timePeriod}}，{{feeRuleVO.exceedLongDistance}}公里)</view>
                <view>{{feeRuleVO.longDistanceFee}}元</view>
              </view>
            </view>
          </view>
        </wd-popup>
        <view @click="clickFeeRule"
          >{{ realFee }}元&nbsp;<wd-icon name="arrow-right" size="34rpx"
        /></view>
      </view>
      <view class="coupon">
        <view>优惠券</view>
        <wd-popup v-model="showCoupon" closable position="bottom">
          <view class="useCoupon">
            <view class="title">请选择优惠券</view>
            <scroll-view class="scroll" scroll-y="true">
              <view v-if="couponRecordVO.length > 0">
                <Coupon
                  @select="clickCoupon"
                  v-for="item in couponRecordVO"
                  :data="item"
                  useRadio
                  :radio="couponId === item.id"
                />
              </view>
              <wd-status-tip v-else image-size="400rpx" image="content" tip="暂无可用优惠券" />
            </scroll-view>
          </view>
        </wd-popup>
        <view @click="selectCoupon"
          >{{
            formatter.format(Number(realFee) - Number(realPayment)) > 0
              ? formatter.format(Number(realPayment) - Number(realFee)) + '元'
              : '未使用优惠券'
          }}&nbsp;<wd-icon name="arrow-right" size="34rpx"
        /></view>
      </view>
      <view class="button">
        <wd-button @click="payOrder" block>钱包支付</wd-button>
      </view>
    </view>
    <view v-else class="info">
      <view class="distance">
        <view class="left">
          距离：{{
            parseFloat(distance) < 1
              ? 1000 * parseFloat(distance) + '米'
              : parseFloat(distance).toFixed(1) + '公里'
          }}
        </view>
        <view class="right">时间：{{ duration }}分钟</view>
      </view>
      <view v-if="role === Role.PASSENGER" class="passenger">
        <view class="avatar">
          <wd-img
            :height="60"
            :width="60"
            round
            :src="
              passengerReceiveOrderVO.driverAvatar != ''
                ? passengerReceiveOrderVO.driverAvatar
                : '/static/images/avatar.png'
            "
          />
        </view>
        <view class="carInfo">
          <view>
            {{ passengerReceiveOrderVO.plateNumber }}&nbsp;·&nbsp;{{
              passengerReceiveOrderVO.carColor
            }}
            &nbsp;&nbsp;{{ passengerReceiveOrderVO.carBrand }}
          </view>
          <view>智行打车&nbsp;·&nbsp;{{ passengerReceiveOrderVO.driverName }}</view>
        </view>
        <view class="phone"><wd-icon color="#4D80F0" name="call" size="26px" /></view>
      </view>
      <view v-else class="driver">
        <view class="info">
          <view class="dot">
            <view class="green" />
          </view>
          <view class="location">{{ locationName }}</view>
          <wd-icon custom-class="phone" color="#4D80F0" name="call" size="26px" />
        </view>
        <view class="button">
          <wd-button @click="clickButton(orderStatus)" block>{{ buttonText }}</wd-button>
        </view>
      </view>
    </view>
  </view>
</template>

<style scoped lang="scss">
.content {
  width: 80%;
  height: 260rpx;
  margin-left: 5%;
  background-color: var(--front-color);
  position: fixed;
  bottom: 160rpx;
  display: flex;
  flex-direction: column;
  padding: 20rpx 5%;
  border-radius: 20rpx;
  .info {
    flex: 3;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    .item {
      display: flex;
      justify-content: space-between;
    }
  }
  .button {
    flex: 2;
  }
}
.orderInfo {
  width: 80%;
  height: 330rpx;
  margin-left: 5%;
  background-color: var(--front-color);
  position: fixed;
  bottom: 100rpx;
  display: flex;
  flex-direction: column;
  padding: 20rpx 5%;
  border-radius: 20rpx;
  .status {
    flex: 3;
    display: flex;
    align-items: center;
    font-size: 36rpx;
  }
  .payment {
    flex: 8;
    display: flex;
    flex-direction: column;
    .paymentFee {
      flex: 3;
      font-size: 46rpx;
      margin-top: -20rpx;
      display: flex;
      align-items: center;
    }
    .realFee {
      flex: 2;
      font-size: 30rpx;
      display: flex;
      justify-content: space-between;
      align-items: center;
      .feeRule {
        width: 500rpx;
        height: 200rpx;
        padding: 20rpx 30rpx;
        display: flex;
        flex-direction: column;
        .title {
          flex: 1;
          display: flex;
          justify-content: center;
        }
        .detail {
          flex: 2;
          .item {
            margin-top: 10rpx;
            display: flex;
            justify-content: space-between;
          }
        }
      }
    }
    .coupon {
      flex: 2;
      font-size: 30rpx;
      display: flex;
      margin-bottom: 10rpx;
      justify-content: space-between;
      align-items: center;
      color: #ff8913;
      .useCoupon {
        height: 666rpx;
        overflow: hidden;
        .title {
          height: 84rpx;
          color: var(--color);
          display: flex;
          justify-content: center;
          align-items: center;
        }
        .scroll {
          height: 582rpx;
        }
      }
    }
    .button {
      flex: 3;
    }
  }
  .info {
    flex: 8;
    display: flex;
    flex-direction: column;
    .distance {
      flex: 2;
      display: flex;
      align-items: center;
      .left {
        flex: 1;
      }
      .right {
        flex: 1;
      }
    }
    .passenger {
      flex: 6;
      display: flex;
      align-items: center;
      .avatar {
        flex: 2;
        height: 100%;
        display: flex;
        align-items: center;
      }
      .carInfo {
        flex: 8;
        height: 70%;
        margin-left: 10rpx;
        margin-bottom: 10rpx;
        display: flex;
        flex-direction: column;
        justify-content: space-evenly;
      }
      .phone {
        flex: 1;
      }
    }
    .driver {
      flex: 6;
      display: flex;
      flex-direction: column;
      .info {
        flex: 11;
        margin-bottom: 20rpx;
        display: flex;
        align-items: center;
        flex-direction: row;
        .dot {
          flex: 1;
          .green {
            width: 20rpx;
            height: 20rpx;
            border-radius: 50%;
            background-color: #0f0;
          }
        }
        .location {
          flex: 20;
          margin-left: 5rpx;
          margin-right: 5rpx;
        }
        .phone {
          flex: 2;
        }
      }
      .button {
        flex: 9;
      }
    }
  }
}
</style>
